#coding=utf-8
'''
Created on 2011-3-26

@author: zarra
极简单的读取Dicom图像文件模块,模拟PyDicom接口
'''
import struct
import json
import numpy as np
#简单的Dicom数据类型到Python Struct 数据类型映射
dicom2python={
                'UL':'L',
                'US':'H'
                }
try:
    from miniDicom_meta import __dicom_dict__
except:
    import dicom_tools
    __dicom_dict__=dicom_tools.init(r'../data/dicom-dict.txt')
    try:
        with file('./miniDicom_meta.py','w') as stream:
            dicom_tools.dump2python(__dicom_dict__, stream)
    except IOError:
        print 'save meta error'
class MetaHead(object):
    def __init__(self,key,type,length):
        global dicom_dict
        self.key=key
        if key in __dicom_dict__:
            self.title=__dicom_dict__[key]['title']
            self.type=type if type != '\x00\x00' else __dicom_dict__[key]['type']
            self.size =  __dicom_dict__[key]['size']
        else:
            self.title='unknow'
            self.type=type
            self.size=1
        self.length=length
    def __repr__(self):
        return json.dumps( {
                     'key':self.key,
                     'title':self.title,
                     'type':self.type,
                     'length':self.length
                     })
class DicomImage(object):
    def __init__(self,stream):
        self.__data__ = {}
        stream.read(128)
        stream.read(4)
        while True:
            try:
                head = self.read_meta_head(stream)
                data = self.read_meta_data(stream, head)
                #if head.title != 'PixelData':
                #    print head,data#,type(data)
                self.__data__[head.title]=data
            except IOError:
                break
        
    def json(self):
        return json.dumps(self.__data__)
    
    def __getattr__(self,key):
        return self.__data__.get(key,None)
    
    def read_meta_head(self,stream):
        buffer = stream.read(8)
        if len(buffer) != 8 :
            #print len(buffer),8
            raise IOError
        else:
            raw= struct.unpack('<2H2cH',buffer)
            meta =MetaHead((raw[0],raw[1]),raw[2]+raw[3],raw[4])
            return meta

    def read_sq_item(self,stream):
        a=[]
        head=self.read_meta_head(stream)
        while head.key != (0xFFFE,0xE00D):
                
            buffer = self.read_meta_data(stream, head)   
            a.append((head,buffer))
            head=self.read_meta_head(stream)
        return a
              
    def read_sq(self,stream,meta_head):
        result =[]
        head=struct.unpack('<2H',stream.read(4))
        while head  != (0xFFFE,0xE0DD):
            print '-'*60
            print head
            
            if head ==(0xFFFE,0xE000):
                length = struct.unpack('<I',stream.read(4))[0]
                if length != 0xffffffff:
                    print length
                    buffer = stream.read(length)      
                    result.append(buffer)
                    head=struct.unpack('<2H',stream.read(4))
                else:
                    buffer = self.read_sq_item(stream)
                    result.append(buffer)
                    head=struct.unpack('<2H',stream.read(4))
            print '-'*60
        head=struct.unpack('<2H',stream.read(4))
        return result

    def read_meta_data(self,stream,meta_head):
        
        length = meta_head.length
        #对于'OB','OW'类型的数据，其字节长度保存在数据段的头四个字节中
        if  meta_head.type == 'OB':
            length = struct.unpack('<I',stream.read(4))[0]
            if length ==0xFFFFFFFF:
                return self.read_sq(stream,meta_head)
        if  meta_head.type == 'OW':
            length = struct.unpack('<I',stream.read(4))[0]
        if meta_head.type  == 'SQ':
            length = struct.unpack('<I',stream.read(4))[0]
            if length == 0xFFFFFFFF:            
                return self.read_sq(stream,meta_head)
            
        buffer = stream.read(length)
        
        if len(buffer) != length:
            #print len(buffer),length
            raise IOError
        else:
            type = meta_head.type
            if  type in dicom2python:
                p_type = dicom2python[type]
                p_v = struct.unpack('<%d%s'%(meta_head.size,p_type),buffer)
                b = p_v[0] if meta_head.size ==1 else p_v
                print meta_head,b
                return b
            if len(buffer)<256:
                print meta_head,buffer
            else:
                print meta_head,len(buffer)
            return buffer
        
def read_file(filename):
    with open(filename,'rb') as stream:
        image = DicomImage(stream)
        return image
            
if __name__=='__main__':
    
    filename = r'../data/001b9fd4.dcm'
    
    
    image = read_file(filename)
    
    height         = image.Rows
    width          = image.Columns
    bits_allocated = image.BitsAllocated
    bits_stored    = image.BitsStored

    
    import dicom
    dicom_image = dicom.read_file(filename)

    vheight         = dicom_image.Rows
    vwidth          = dicom_image.Columns
    vbits_allocated = dicom_image.BitsAllocated
    vbits_stored    = dicom_image.BitsStored

    #用miniDicom读取的值和PyDicom读取的值相比较
    vdata = dicom_image.PixelData
    test_template = ''''%(v)s:%%s'%%(str(%(v)s == v%(v)s)) ''' 
    def test_var(var):
        code = test_template%{'v':var}
        return eval(code)
    #print test_template%{'v':'height'}
    #print 'height:%s'%(str(height==vheight))
    print test_var('height')
    print test_var('width')
    print test_var('bits_stored')
    #print test_var('data')
    #print type(data[0]),type(data[1])
    print len(vdata)
    print height,width
    data = image.PixelData[1]
    print len(data)
    size = len(data)/2
    f=file("output.jpg","wb")
    f.write(data)
    f.close()
    
    #data = data.reshape(size/width,width)
       